/*
 * 本文件是构造Decaf编译器所需要的JFlex输入脚本。
 * 在第一阶段，你需要完成这个脚本的内容，请参考"JFlex Manual"中关于如何编写JFlex脚本的说明。
 *
 * 注意：在UNIX系统下你需要保证这个文件使用UNIX文本格式，可使用dos2unix命令进行文本各式转换。
 */

package decaf.frontend;

import decaf.Location;
import decaf.error.*;
import decaf.utils.MiscUtils;
 
%%
	//jflex选项
%public
%class Lexer
%extends BaseLexer
%byaccj
%line
%column
%switch
%unicode
	//用户自定义内容
%{
	private Location sloc = null;
	private StringBuilder buffer = new StringBuilder();

	public Location getLocation() {
		return new decaf.Location(yyline + 1, yycolumn + 1);
	}
%}
      //预定义宏
NEWLINE				= (\r|\n|\r\n)
DIGIT 				= ([0-9])
HEX_DIGIT 			= ([0-9A-Fa-f])
HEX_INTEGER			= (0[Xx]{HEX_DIGIT}+)
DEC_INTEGER			= ({DIGIT}+)
INTEGER				= ({HEX_INTEGER}|{DEC_INTEGER})
IDENTIFIER			= ([A-Za-z][_0-9A-Za-z]*)
UNARY_OPERATOR		= ("+"|"-"|"*"|"/"|"%"|"="|"<"|">"|"."|","|";"|"!"|"("|")"|"["|"]"|"{"|"}")
S_COMMENT			= ("//"[^\r\n]*{NEWLINE})
WHITESPACE			= ([ \t]+)
STRING				= (\"[^\n]*\")
TEMP1STRING 		= ([^\n\"]*\n[^\n\"]*)
TEMP2STRING			= (\"{TEMP1STRING}+)
ENDSTRING			= (\"[^\"]*)
ERRORSTRING			= ({TEMP2STRING}\")

	// 开始条件S表示字符串
%x S

%%
	// 识别注释和空白字符的规则
{WHITESPACE}		{ /* Just ignore */    }
{NEWLINE}			{ /* Just ignore */    }
{S_COMMENT}			{ /* Just ignore */    }


	// 识别关键字的规则 
"void"				{ return keyword(Parser.VOID);}
"bool"				{ return keyword(Parser.BOOL);}
"int"				{ return keyword(Parser.INT);}
"string"			{ return keyword(Parser.STRING);}
"class"				{ return keyword(Parser.CLASS);}
"null"				{ return keyword(Parser.NULL);}
"extends"			{ return keyword(Parser.EXTENDS);}
"this"				{ return keyword(Parser.THIS);}
"while"				{ return keyword(Parser.WHILE);}
"for"				{ return keyword(Parser.FOR);}
"if"				{ return keyword(Parser.IF);}
"else"				{ return keyword(Parser.ELSE);}
"return"			{ return keyword(Parser.RETURN);}
"break"				{ return keyword(Parser.BREAK);}
"new"				{ return keyword(Parser.NEW);}
"static"			{ return keyword(Parser.STATIC);}
"Print"				{ return keyword(Parser.PRINT);}
"ReadInteger"		{ return keyword(Parser.READ_INTEGER);}
"ReadLine"			{ return keyword(Parser.READ_LINE);}
"instanceof"		{ return keyword(Parser.INSTANCEOF);}

	// 识别操作符的规则
"<="				{ return operator(Parser.LESS_EQUAL);	}
">="				{ return operator(Parser.GREATER_EQUAL);	}
"=="				{ return operator(Parser.EQUAL);	}
"!="				{ return operator(Parser.NOT_EQUAL);	}
"&&"				{ return operator(Parser.AND);	}
"||"				{ return operator(Parser.OR);	}
{UNARY_OPERATOR}	{ return operator((int)yytext().charAt(0)); }

	// 识别常数的规则
"true"				{ return boolConst(true);}
"false"				{ return boolConst(false);}
{INTEGER}			{ return intConst(yytext());}
{STRING}			{ 
						buffer.delete(0,buffer.capacity());
						for (int i = 1; i < yytext().length()-1; i++) {
							if(yytext().charAt(i)=='\\')
							{
								char c = yytext().charAt(i+1);
								switch (c) {								
									case 'r':
									{
										buffer.append('\r');
										i++;
										break;										
									}
									case 'n':
									{
										buffer.append('\n');
										i++;
										break;										
									}
									case 't':
									{
										buffer.append('\t');
										i++;
										break;										
									}									
									case '"':
									{
										buffer.append('\"');
										i++;
										break;										
									}
									case '\\':
									{
										buffer.append('\\');
										i++;
										break;										
									}
								}
							}
							else
								buffer.append(yytext().charAt(i));

						}
						return StringConst(buffer.toString(),getLocation());
						
					}
	// 识别标识符的规则
{IDENTIFIER}		{ return identifier(yytext());}
	// 上面规则不能识别的字符怎么处理
["$"|"#"|"@"|"?"]	{ issueError((new UnrecogCharError(getLocation(),yytext().charAt(0))));} 
{ERRORSTRING}		{
						buffer.delete(0,buffer.capacity());
						for (int i = 1; i < yytext().length()-1; i++) {
							char c = yytext().charAt(i);
							if(c!='\n'&&c!='\t'&&c!=' ')
								buffer.append(yytext().charAt(i));
						}
						issueError((new NewlineInStrError(getLocation(),"\""+buffer.toString()+"\"")));
						return StringConst(buffer.toString(),getLocation());
					}
{ENDSTRING}			{
						buffer.delete(0,buffer.capacity());
						for (int i = 1; i < yytext().length(); i++) {
							char c = yytext().charAt(i);
							if(c!='\n'&&c!='\t'&&c!=' ')
								buffer.append(yytext().charAt(i));
						}						
						issueError((new UntermStrError(getLocation(),"\""+buffer.toString()+"\"")));
					}
